/* tview.c is part of VIP program
 * Written by J. Salvador Arias, 2010
 *      CONICET, INSUE, Instituto Miguel Lillo,
 *      Miguel Lillo 205, S.M. de Tucuman (4000)
 *      Tucuman, Argentina
 *      e-mail: jsalarias@csnat.unt.edu.ar
 *
 * VIP is a free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation and
 * Creative Commons.
 *
 * This file and the VIP program is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * To view a copy of this license, visit
 * http://creativecommons.org/licenses/GPL/2.0/
 * or send a letter to
 * Creative Commons, 171 Second Street, Suite 300,
 * San Francisco, California, 94105, USA.
 */

#include "wins.h"
#include "dialogs.h"
#include "grid.h"
#include "parser.h"
#include "out.h"
#include <string.h>

typedef struct tagTREEVIEWWINDATA TREEVIEWWINDATA;
struct tagTREEVIEWWINDATA {
 GtkWidget* drawable;
 GdkPixmap* pixMap;

 GdkGC* blackPen;
 GdkGC* greenPen;
 GdkGC* whitePen;
 GdkGC* greyPen;
 GdkGC* bluePen;
 GdkGC* redPen;

 GtkWidget* menuFormat;
 GtkWidget* menuAlign;
 GtkWidget* menuRagged;
 GtkWidget* menuChrono;
 GtkWidget* menuToTerm;
 GtkWidget* menuToRoot;
 GtkWidget* menuFile;

 GtkWidget* menuRecons;
 GtkWidget* menuSupported;
 GtkWidget* menuCommon;
 GtkWidget* menuBremer;

 gint clientX;
 gint clientY;
 SCOUNTER width;
 SCOUNTER height;
 SINTEGER originX;
 SINTEGER originY;
 SINTEGER endClient;
 SINTEGER maxX;
 SINTEGER maxY;
 gint prevX;
 gint prevY;

 SFLAG alignment;
 SFLAG modeRec;
};

static gint OnDelete (GtkWidget* treeWin, GdkEvent* event, gpointer data);
static gint OnExpose (GtkWidget* drawable, GdkEventExpose* event, gpointer data);
static gint OnConfigure (GtkWidget* drawable, GdkEvent* event, gpointer data);

static gint OnKey (GtkWidget* treeWin, GdkEventKey* event, gpointer data);
static gint OnMouseWheel (GtkWidget* drawable, GdkEventScroll* event, gpointer data);
static gint OnMotion (GtkWidget* drawable, GdkEventMotion* event, gpointer data);
static gint OnMouseButton (GtkWidget* drawable, GdkEventButton* event, gpointer data);

static void OnAlign (GtkWidget* menuItem, gpointer data);
#define TREE_TOROOT  1
#define TREE_TOTERM  2
#define TREE_RAGGED  4
#define TREE_ALIGN   8
#define TREE_CHRONO 16

#define MENU_TOROOT "toRoot"
#define MENU_TOTERM "toTerm"
#define MENU_RAGGED "ragged"
#define MENU_ALIGN  "align"
#define MENU_CHRONO "chrono"

static void OnMenuFitToWin (GtkWidget* menuItem, gpointer data);
static void OnMenuFitToTerm (GtkWidget* menuItem, gpointer data);

static void OnMenuSaveTree (GtkMenuItem* saveTreeMenu, gpointer data);
static void OnMenuSaveGraph (GtkMenuItem* saveGraphMenu, gpointer data);
static void OnMenuTreeName (GtkMenuItem* nameMenu, gpointer data);

static void OnMenuSortUp (GtkWidget* menuSort, gpointer data);
static void OnMenuSortDown (GtkWidget* menuSort, gpointer data);
static void OnMenuSortMix (GtkWidget* menuSort, gpointer data);
static void OnMenuSortDef (GtkWidget* menuSort, gpointer data);
static void OnMenuOptions (GtkWidget* menuOption, gpointer data);

static void DrawTree (SFLAG redraw);
static void PaintTree ();
static void PutTreeOnScreen (PHYLOTREE* tree);

static GNode* SearchNearestPoint (gint x, gint y);
static void OnChangeNodeData (GNode* node);

static TREEVIEWWINDATA tWinData;

#define EDIT_TREE_REC 1
#define VIEW_TREE_REC 0

void StartTreeViewWindow () {
 GtkWidget* gBox;
 GtkWidget* menuBar;
 GtkWidget* menu;
 GtkWidget* menuItem;
 GtkAccelGroup* accelGroup;
 GSList* group;

 GdkColor blueColor = {0, 0x0000, 0x0000, 0xFFFF};
 GdkColor greenColor = {0, 0x0000, 0xFFFF, 0x0000};
 GdkColor redColor = {0, 0xFFFF, 0x0000, 0x0000};
 GdkColor greyColor = {0, 0x6000, 0x6000, 0x6000};

 tWinData . pixMap = NULL;
 gBox = gtk_vbox_new (FALSE, 0);
 treeViewWindow = CreateWindow ("VIP: Tree view window", 250, 0, 400, 600, G_CALLBACK (OnDelete), gBox);

 tWinData . modeRec = VIEW_TREE_REC;

 /* --- Sets menues --- */
 accelGroup = gtk_accel_group_new ();
 gtk_window_add_accel_group (GTK_WINDOW (treeViewWindow), accelGroup);
 menuBar = gtk_menu_bar_new ();
 gtk_box_pack_start (GTK_BOX (gBox), menuBar, FALSE, TRUE, 0);
 gtk_widget_show (menuBar);
 /* File */
 menu = gtk_menu_new ();
 CreateMenuItem (menu, "Tree _name...", accelGroup, GDK_I, GDK_CONTROL_MASK, G_CALLBACK (OnMenuTreeName), NULL);
 CreateMenuSeparator (menu);
 CreateMenuItem (menu, "Save _tree...", accelGroup, GDK_T, GDK_CONTROL_MASK | GDK_SHIFT_MASK, G_CALLBACK (OnMenuSaveTree), NULL);
 CreateMenuItem (menu, "Save tree _graphic...", accelGroup, GDK_G, GDK_CONTROL_MASK | GDK_SHIFT_MASK, G_CALLBACK (OnMenuSaveGraph), NULL);
 tWinData . menuFile = AddMenuToBar (menu, "_File", menuBar);
 gtk_widget_set_sensitive (tWinData . menuFile, FALSE);
 /* Format */
 menu = gtk_menu_new ();
 group = NULL;
 tWinData . menuAlign = CreateMenuItemRadio (menu, "_Aligned terms", accelGroup, GDK_A, GDK_CONTROL_MASK,
                                             G_CALLBACK (OnAlign), MENU_ALIGN, group);
 group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (tWinData . menuAlign));
 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuAlign), TRUE);
 tWinData . menuRagged = CreateMenuItemRadio (menu, "_Ragged terms", accelGroup, GDK_R, GDK_CONTROL_MASK,
                                              G_CALLBACK (OnAlign), MENU_RAGGED, group);
 group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (tWinData . menuRagged));
 tWinData . menuChrono = CreateMenuItemRadio (menu, "_Chrono tree", accelGroup, GDK_C, GDK_CONTROL_MASK,
                                              G_CALLBACK (OnAlign), MENU_CHRONO, group);
 gtk_widget_set_sensitive (tWinData . menuChrono, FALSE);
 CreateMenuSeparator (menu);
 group = NULL;
 tWinData . menuToTerm = CreateMenuItemRadio (menu, "Pull nodes to t_erms", accelGroup, GDK_E, GDK_CONTROL_MASK,
                                                 G_CALLBACK (OnAlign), MENU_TOTERM, group);
 group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (tWinData . menuToTerm));
 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuToTerm), TRUE);
 tWinData . menuToRoot = CreateMenuItemRadio (menu, "Pull nodes to r_oot", accelGroup, GDK_O, GDK_CONTROL_MASK,
                                              G_CALLBACK (OnAlign), MENU_TOROOT, group);
 CreateMenuSeparator (menu);
 CreateMenuItem (menu, "Sort _up", accelGroup, GDK_U, GDK_CONTROL_MASK, G_CALLBACK (OnMenuSortUp), NULL);
 CreateMenuItem (menu, "Sort _down", accelGroup, GDK_D, GDK_CONTROL_MASK, G_CALLBACK (OnMenuSortDown), NULL);
 CreateMenuItem (menu, "_Mixed sorting", accelGroup, GDK_M, GDK_CONTROL_MASK, G_CALLBACK (OnMenuSortMix), NULL);
 CreateMenuItem (menu, "_Default sorting", accelGroup, GDK_G, GDK_CONTROL_MASK, G_CALLBACK (OnMenuSortDef), NULL);
 CreateMenuSeparator (menu);
 CreateMenuItem (menu, "Fit tree to _window", accelGroup, GDK_F, GDK_CONTROL_MASK, G_CALLBACK (OnMenuFitToWin), NULL);
 CreateMenuItem (menu, "Fit tree to _terms", accelGroup, GDK_T, GDK_CONTROL_MASK, G_CALLBACK (OnMenuFitToTerm), NULL);
 tWinData . menuFormat = AddMenuToBar (menu, "Forma_t", menuBar);
 gtk_widget_set_sensitive (tWinData . menuFormat, FALSE);
 /* Reconstruction */
 menu = gtk_menu_new ();
 group = NULL;
 menuItem = CreateMenuItemRadio (menu, "_All reconstruction", accelGroup, GDK_L, GDK_CONTROL_MASK,
                                             G_CALLBACK (OnMenuOptions), NULL, group);
 group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuItem));
 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuItem), TRUE);
 tWinData . menuSupported = CreateMenuItemRadio (menu, "_Supported reconstructions (on consensus)", accelGroup, GDK_S, GDK_CONTROL_MASK,
                                                 G_CALLBACK (OnMenuOptions), NULL, group);
 group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (tWinData . menuSupported));
 tWinData . menuCommon = CreateMenuItemRadio (menu, "_Common reconstructions (on consensus)", accelGroup, GDK_N, GDK_CONTROL_MASK,
                                                 G_CALLBACK (OnMenuOptions), NULL, group);
 tWinData . menuRecons = AddMenuToBar (menu, "_Reconstruction", menuBar);
 CreateMenuSeparator (menu);
 tWinData . menuBremer = CreateMenuItemCheck (menu, "_Bremer\'s support", accelGroup, GDK_B, GDK_CONTROL_MASK,
                                                    G_CALLBACK (OnMenuOptions), NULL);
 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuBremer), FALSE);
 gtk_widget_set_sensitive (tWinData . menuRecons, FALSE);


 /* --- Drawing area --- */
 tWinData . alignment = TREE_TOTERM | TREE_ALIGN;
 tWinData . drawable = gtk_drawing_area_new ();
 gtk_box_pack_start (GTK_BOX (gBox), tWinData . drawable, TRUE, TRUE, 0);
 gtk_widget_show (tWinData . drawable);
 g_signal_connect (G_OBJECT (tWinData . drawable), "expose_event", G_CALLBACK (OnExpose), NULL);
 g_signal_connect (G_OBJECT (tWinData . drawable), "configure_event", G_CALLBACK (OnConfigure), NULL);

 gtk_widget_add_events (treeViewWindow, GDK_KEY_PRESS_MASK);
 g_signal_connect (G_OBJECT (treeViewWindow), "key_press_event", G_CALLBACK (OnKey), NULL);
 gtk_widget_add_events (tWinData . drawable, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_SCROLL_MASK);
 g_signal_connect (G_OBJECT (tWinData . drawable), "motion_notify_event", G_CALLBACK (OnMotion), NULL);
 g_signal_connect (G_OBJECT (tWinData . drawable), "button_press_event", G_CALLBACK (OnMouseButton), NULL);
 g_signal_connect (G_OBJECT (tWinData . drawable), "scroll_event", G_CALLBACK (OnMouseWheel), NULL);

 gtk_widget_show (treeViewWindow);

 tWinData . blackPen = gdk_gc_new (tWinData . drawable -> window);
 gdk_gc_copy (tWinData . blackPen, tWinData . drawable -> style -> black_gc);

 tWinData . greenPen = gdk_gc_new (tWinData . drawable -> window);
 gdk_gc_copy (tWinData . greenPen, tWinData . drawable -> style -> black_gc);
 gdk_gc_set_rgb_fg_color (tWinData . greenPen, &greenColor);

 tWinData . greyPen = gdk_gc_new (tWinData . drawable -> window);
 gdk_gc_copy (tWinData . greyPen, tWinData . drawable -> style -> black_gc);
 gdk_gc_set_rgb_fg_color (tWinData . greyPen, &greyColor);

 tWinData . whitePen = gdk_gc_new (tWinData . drawable -> window);
 gdk_gc_copy (tWinData . whitePen, tWinData . drawable -> style -> white_gc);

 tWinData . bluePen = gdk_gc_new (tWinData . drawable -> window);
 gdk_gc_copy (tWinData . bluePen, tWinData . drawable -> style -> black_gc);
 gdk_gc_set_rgb_fg_color (tWinData . bluePen, &blueColor);

 tWinData . redPen = gdk_gc_new (tWinData . drawable -> window);
 gdk_gc_copy (tWinData . redPen, tWinData . drawable -> style -> black_gc);
 gdk_gc_set_rgb_fg_color (tWinData . redPen, &redColor);
}

void OpenNewTree () {
 PHYLOTREE* tree;

 if ((activeTree == NULL) && (GETTREES != NULL)) {
   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuAlign), TRUE);
   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuToTerm), TRUE);
   activeTree = GETTREES;
   tree = (PHYLOTREE*) activeTree -> data;
   if (activeNode == NULL)
     activeNode = tree -> root;
   gtk_window_set_title (GTK_WINDOW (treeViewWindow), tree -> name);
   if (tree -> x == 0)
    tree -> x = tWinData . width = tWinData . clientX;
   else
     tWinData . width = tree -> x;
   if (tree -> y == 0)
    tree -> y = tWinData . height = tWinData . clientY;
   else
     tWinData . height = tree -> y;
   tWinData . originX = tWinData . originY = 0;
   tWinData . endClient = 50;
   DrawTree (TRUE);
   if ((tree -> maxTreeAge > 0) && (tree -> maxTreeAge != NO_AGE))
     gtk_widget_set_sensitive (tWinData . menuChrono, TRUE);
   gtk_widget_set_sensitive (tWinData . menuFormat, TRUE);
   if (tree -> recCons != NULL)
     gtk_widget_set_sensitive (tWinData . menuRecons, TRUE);
   else
     gtk_widget_set_sensitive (tWinData . menuRecons, FALSE);
   gtk_widget_set_sensitive (tWinData . menuFile, TRUE);
 }
}

void OnChangeTree (GList* nuTree) {
 PHYLOTREE* tree;

 if (nuTree != NULL) {
   tree = (PHYLOTREE*) nuTree -> data;
   activeTree = nuTree;
   gtk_window_set_title (GTK_WINDOW (treeViewWindow), tree -> name);
   if (tree -> x == 0)
    tree -> x = tWinData . width = tWinData . clientX;
   else
     tWinData . width = tree -> x;
   if (tree -> y == 0)
    tree -> y = tWinData . height = tWinData . clientY;
   else
     tWinData . height = tree -> y;
   tWinData . originX = tWinData . originY = 0;
   tWinData . endClient = 50;
   gtk_widget_set_sensitive (tWinData . menuFormat, TRUE);
   if (tree -> recCons != NULL)
     gtk_widget_set_sensitive (tWinData . menuRecons, TRUE);
   else
     gtk_widget_set_sensitive (tWinData . menuRecons, FALSE);
   if ((tree -> maxTreeAge > 0) && (tree -> maxTreeAge != NO_AGE))
     gtk_widget_set_sensitive (tWinData . menuChrono, TRUE);
   else {
     if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (tWinData . menuChrono)) == TRUE) {
       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuAlign), TRUE);
       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuToTerm), TRUE);
     }
     gtk_widget_set_sensitive (tWinData . menuChrono, FALSE);
   }
 }
 else {
   activeTree = NULL;
   gtk_window_set_title (GTK_WINDOW (treeViewWindow), "VIP: Tree view window");
   gtk_widget_set_sensitive (tWinData . menuFormat, FALSE);
   gtk_widget_set_sensitive (tWinData . menuRecons, FALSE);
   gtk_widget_set_sensitive (tWinData . menuFile, FALSE);
   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuAlign), TRUE);
   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuToTerm), TRUE);
   gtk_widget_set_sensitive (tWinData . menuChrono, FALSE);
 }
 DrawTree (TRUE);
}

void OnUpdateTree () {
 PHYLOTREE* tree;

 if (activeTree == NULL) return;
 tree = (PHYLOTREE*) activeTree -> data;
 if (tree -> recCons != NULL)
   gtk_widget_set_sensitive (tWinData . menuRecons, TRUE);
 else
   gtk_widget_set_sensitive (tWinData . menuRecons, FALSE);
 DrawTree (FALSE);
}

void SetRecEdition (SFLAG mode) {
 tWinData . modeRec = (mode == TRUE) ? EDIT_TREE_REC : VIEW_TREE_REC;
}

gint OnDelete (GtkWidget* treeWin, GdkEvent* event, gpointer data) {
 gtk_window_iconify (GTK_WINDOW (treeViewWindow));
 return TRUE;
}

gint OnExpose (GtkWidget* drawable, GdkEventExpose* event, gpointer data) {
 gdk_draw_pixmap (tWinData . drawable -> window, tWinData . drawable -> style -> fg_gc [GTK_WIDGET_STATE (tWinData . drawable)],
     tWinData . pixMap, event -> area . x, event -> area . y, event -> area . x, event -> area . y,
     event -> area . width, event -> area . height);
 return FALSE;
}

gint OnConfigure (GtkWidget* drawable, GdkEvent* event, gpointer data) {
 tWinData . clientX = tWinData . drawable -> allocation . width;
 tWinData . clientY = tWinData . drawable -> allocation . height;
 if (activeTree == NULL) {
   tWinData . width = tWinData . clientX;
   tWinData . height = tWinData . clientY;
 }
 if (tWinData . pixMap)
   gdk_pixmap_unref (tWinData . pixMap);
 tWinData . pixMap = gdk_pixmap_new (tWinData . drawable -> window, tWinData . clientX, tWinData . clientY, -1);
 DrawTree (FALSE);
 return TRUE;
}

gint OnMouseButton (GtkWidget* drawable, GdkEventButton* event, gpointer data) {
 GNode* actNode;
 PHYLONODE* toChange;
 PHYLOTREE* tree;
 SCOUNTER actFill, nuFill;
 ENTRYDIALOG* radiusDialog;
 gchar* entry;


 if (activeTree == NULL) return FALSE;
 if ((event -> type == GDK_BUTTON_PRESS) && (event -> button == 1) &&
     (!(event -> state & GDK_SHIFT_MASK)) && (!(event -> state & GDK_CONTROL_MASK))) {
   actNode = SearchNearestPoint (event -> x + tWinData . originX, event -> y + tWinData . originY);
   if ((actNode != NULL) && (actNode != activeNode)) {
     activeNode = actNode;
     DrawTree (FALSE);
     ChangeGeo ();
     OnChangeRec ();
   }
 }
 else if ((event -> type == GDK_BUTTON_PRESS) && (event -> button == 3) &&
          (!(event -> state & GDK_SHIFT_MASK)) && (event -> state & GDK_CONTROL_MASK)) {
   tree = (PHYLOTREE*) activeTree -> data;
   if (tree -> actRec == NULL) return FALSE;
   actNode = SearchNearestPoint (event -> x + tWinData . originX, event -> y + tWinData . originY);
   if (actNode != NULL) {
     if (tWinData . modeRec == EDIT_TREE_REC) {
       ChangeNode (actNode);
       SetTreeBestScore (tree);
       DrawTree (FALSE);
       ChangeGeo ();
       OnChangeRec ();
     }
   }
 }
 else if ((event -> type == GDK_BUTTON_PRESS) && (event -> button == 3) &&
          (event -> state & GDK_SHIFT_MASK) && (!(event -> state & GDK_CONTROL_MASK))) {
   actNode = SearchNearestPoint (event -> x + tWinData . originX, event -> y + tWinData . originY);
   if (actNode != NULL) {
     toChange = (PHYLONODE*) actNode -> data;
     actFill = (toChange -> fill > GETFILL) ? GETFILL : toChange -> fill;
     radiusDialog = CounterEntryDialog (GTK_WINDOW (treeViewWindow), actFill, "Set fill", "New fill value");
     if (gtk_dialog_run (GTK_DIALOG (radiusDialog -> dialog)) == GTK_RESPONSE_ACCEPT) {
       entry = g_strdup_printf (gtk_entry_get_text (GTK_ENTRY (radiusDialog -> entry)));
       SetCommandLine (entry);
       g_free (entry);
       if (GetCmdNumber (&nuFill) != FALSE) {
         if (nuFill != actFill)
           PutFillValue (toChange, nuFill);
       }
     }
     DestroyEntryDialog (radiusDialog);
   }
 }
 else if ((event -> type == GDK_BUTTON_PRESS) && (event -> button == 3) &&
          (!(event -> state & GDK_SHIFT_MASK)) && (!(event -> state & GDK_CONTROL_MASK))) {
   actNode = SearchNearestPoint (event -> x + tWinData . originX, event -> y + tWinData . originY);
   if (actNode != NULL)
     OnChangeNodeData (actNode);
 }
 return FALSE;
}

gint OnMouseWheel (GtkWidget* drawable, GdkEventScroll* event, gpointer data) {
 SFLAG updatePos;

 if (activeTree == NULL) return FALSE;
 updatePos = FALSE;
 switch (event -> direction){
  case GDK_SCROLL_UP: tWinData . originY -= 5;
       updatePos = TRUE;
       break;
  case GDK_SCROLL_DOWN: tWinData . originY += 5;
       updatePos = TRUE;
       break;
  default: break;
 }
 if (updatePos == TRUE) {
   if (tWinData . originX < - (tWinData . clientX - 10))
     tWinData . originX = - (tWinData . clientX - 10);
   if (tWinData . originX > (tWinData . maxX - 5))
     tWinData . originX = tWinData . maxX - 5;
   if (tWinData . originY < - (tWinData . clientY - 10))
     tWinData . originY = - (tWinData . clientY - 10);
   if (tWinData . originY > (tWinData . maxY - 5))
     tWinData . originY = tWinData . maxY - 5;
   DrawTree (FALSE);
 }
 return FALSE;
}

gint OnKey (GtkWidget* treeWin, GdkEventKey* event, gpointer data) {
 SCOUNTER nuSz;
 SFLAG updatePos;
 SFLAG draw;
 SFLAG nuTree;
 SFLAG nuNode;
 PHYLOTREE* tree;

 if (activeTree == NULL) return FALSE;
 updatePos = FALSE;
 draw = FALSE;
 nuTree = FALSE;
 nuNode = FALSE;
 switch (event -> keyval) {
  case GDK_plus:
  case GDK_KP_Add: if (event -> state & GDK_CONTROL_MASK) {
         nuSz = (tWinData . height / 100);
         if (nuSz < 5)
           nuSz = 5;
         tWinData . height += nuSz;
         draw = TRUE;
       }
       else if (event -> state & GDK_SHIFT_MASK) {
         nuSz = (tWinData . width / 100);
         if (nuSz < 5)
           nuSz = 5;
         tWinData . width += nuSz;
         draw = TRUE;
       }
       break;
  case GDK_minus:
  case GDK_KP_Subtract: if ((event -> state & GDK_CONTROL_MASK) && (tWinData . height > 5)) {
         nuSz = (tWinData . height / 100);
         if (nuSz < 5)
           nuSz = 5;
         tWinData . height -= nuSz;
         if (tWinData . height < 5)
           tWinData . height = 5;
         draw = TRUE;
       }
       else if ((event -> state & GDK_SHIFT_MASK) && (tWinData . width > 5)) {
         nuSz = (tWinData . width / 100);
         if (nuSz < 5)
           nuSz = 5;
         tWinData . width -= nuSz;
         if (tWinData . width < 5)
           tWinData . width = 5;
         draw = TRUE;
       }
       break;
  case GDK_Up:
  case GDK_KP_Up: if (event -> state & GDK_CONTROL_MASK) {
         nuSz = (tWinData . height / 100);
         if (nuSz < 5)
           nuSz = 5;
         tWinData . height -= nuSz;
         if (tWinData . height < 5)
           tWinData . height = 5;
         draw = TRUE;
       }
       else {
         tWinData . originY -= 5;
         updatePos = TRUE;
       }
       break;
  case GDK_Down:
  case GDK_KP_Down: if ((event -> state & GDK_CONTROL_MASK) && (tWinData . height > 5)) {
         nuSz = (tWinData . height / 100);
         if (nuSz < 5)
           nuSz = 5;
         tWinData . height += nuSz;
         draw = TRUE;
       }
       else {
         tWinData . originY += 5;
         updatePos = TRUE;
       }
       break;
  case GDK_Left:
  case GDK_KP_Left: if (event -> state & GDK_CONTROL_MASK) {
         nuSz = (tWinData . width / 100);
         if (nuSz < 5)
           nuSz = 5;
         tWinData . width -= nuSz;
         if (tWinData . width < 5)
           tWinData . width = 5;
         draw = TRUE;
       }
       else {
         tWinData . originX -= 5;
         updatePos = TRUE;
       }
       break;
  case GDK_Right:
  case GDK_KP_Right: if ((event -> state & GDK_CONTROL_MASK) && (tWinData . width > 5)) {
         nuSz = (tWinData . width / 100);
         if (nuSz < 5)
           nuSz = 5;
         tWinData . width += nuSz;
         draw = TRUE;
       }
       else {
         tWinData . originX += 5;
         updatePos = TRUE;
       }
       break;
  case GDK_Page_Up:
  case GDK_KP_Page_Up: tWinData . originY -= tWinData . clientY;
       updatePos = TRUE;
       break;
  case GDK_Page_Down:
  case GDK_KP_Page_Down: tWinData . originY += tWinData . clientY;
       updatePos = TRUE;
       break;
  case GDK_Home:
  case GDK_KP_Home: if (event -> state & GDK_CONTROL_MASK) {
         if (GETTREES != activeTree) {
           activeTree = GETTREES;
           nuTree = TRUE;
         }
       }
       else {
         tWinData . originX = tWinData . originY = 0;
         updatePos = TRUE;
       }
       break;
  case GDK_End:
  case GDK_KP_End: if (event -> state & GDK_CONTROL_MASK) {
         if (GETLASTTREE != activeTree) {
           activeTree = GETLASTTREE;
           nuTree = TRUE;
         }
       }
       else {
         tWinData . originX = tWinData . maxX - 5;
         tWinData . originY = tWinData . maxY - 5;
         updatePos = TRUE;
       }
       break;
  case GDK_space:
  case GDK_Return:
  case GDK_KP_Enter: if (event -> state & GDK_CONTROL_MASK) {
         activeNode = GetNextNode (activeNode);
         nuNode = TRUE;
       }
       else if (g_list_next (activeTree) != NULL) {
         activeTree = g_list_next (activeTree);
         nuTree = TRUE;
       }
       break;
  case GDK_BackSpace: if (event -> state & GDK_CONTROL_MASK) {
         activeNode = GetPrevNode (activeNode);
         nuNode = TRUE;
       }
       else if (g_list_previous (activeTree) != NULL) {
         activeTree = g_list_previous (activeTree);
         nuTree = TRUE;
       }
       break;
 }
 if (nuTree == TRUE) {
   tree = (PHYLOTREE*) activeTree -> data;
   if ((tree -> maxTreeAge > 0) && (tree -> maxTreeAge != NO_AGE))
     gtk_widget_set_sensitive (tWinData . menuChrono, TRUE);
   else {
     gtk_widget_set_sensitive (tWinData . menuChrono, FALSE);
     if (tWinData . alignment & TREE_CHRONO) {
       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuRagged), TRUE);
       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuToRoot), TRUE);
       tWinData . alignment = TREE_RAGGED | TREE_TOROOT;
     }
   }
   gtk_window_set_title (GTK_WINDOW (treeViewWindow), tree -> name);
   if (tree -> x == 0) {
    tWinData . width = tWinData . clientX;
    tree -> x = tWinData . width;
   }
   else
     tWinData . width = tree -> x;
   if (tree -> y == 0) {
    tWinData . height = tWinData . clientY;
    tree -> y = tWinData . height;
   }
   else
     tWinData . height = tree -> y;
   tWinData . originX = tWinData . originY = 0;
   tWinData . width = tWinData . clientX;
   tWinData . height = tWinData . clientY;
   tWinData . endClient = 50;
   DrawTree (TRUE);
   OnChangeRec ();
 }
 else if (nuNode == TRUE) {
   DrawTree (FALSE);
   ChangeGeo ();
 }
 else if (updatePos == TRUE) {
   if (tWinData . originX < - (tWinData . clientX - 10))
     tWinData . originX = - (tWinData . clientX - 10);
   if (tWinData . originX > (tWinData . maxX - 5))
     tWinData . originX = tWinData . maxX - 5;
   if (tWinData . originY < - (tWinData . clientY - 10))
     tWinData . originY = - (tWinData . clientY - 10);
   if (tWinData . originY > (tWinData . maxY - 5))
     tWinData . originY = tWinData . maxY - 5;
   DrawTree (draw);
 }
 else if (draw == TRUE) {
   tree = (PHYLOTREE*) activeTree -> data;
   tree -> x = tWinData . width;
   tree -> y = tWinData . height;
   DrawTree (draw);
 }
 return FALSE;
}

gint OnMotion (GtkWidget* drawable, GdkEventMotion* event, gpointer data) {
 SINTEGER nu;
 if (activeTree == NULL) return FALSE;
 if (event -> state & GDK_BUTTON1_MASK) {
   if ((tWinData . prevX != 0) || (tWinData . prevY != 0)) {
     nu = event -> x - tWinData . prevX;
     tWinData . originX -= nu;
     if (tWinData . originX < - (tWinData . clientX - 10))
       tWinData . originX = - (tWinData . clientX - 10);
     else if (tWinData . originX > (tWinData . maxX - 5))
       tWinData . originX = tWinData . maxX - 5;
     nu = event -> y - tWinData . prevY;
     tWinData . originY -= nu;
     if (tWinData . originY < - (tWinData . clientY - 10))
       tWinData . originY = - (tWinData . clientY - 10);
     else if (tWinData . originY > (tWinData . maxY - 5))
       tWinData . originY = tWinData . maxY - 5;
     DrawTree (FALSE);
   }
   tWinData . prevX = event -> x;
   tWinData . prevY = event -> y;
 }
 else {
   tWinData . prevX = 0;
   tWinData . prevY = 0;
 }
 return TRUE;
}

void OnMenuTreeName (GtkMenuItem* nameMenu, gpointer data) {
 ENTRYDIALOG* nameDialog;
 PHYLOTREE* tree;
 gchar* entry;

 if (activeTree == NULL) return;
 tree = (PHYLOTREE*) activeTree -> data;
 nameDialog = TextEntryDialog (GTK_WINDOW (mapWindow), tree -> name, "Set tree name", "Tree");
 if (gtk_dialog_run (GTK_DIALOG (nameDialog -> dialog)) == GTK_RESPONSE_ACCEPT) {
   entry = g_strdup_printf (gtk_entry_get_text (GTK_ENTRY (nameDialog -> entry)));
   if (strlen (entry) > 0) {
     if (tree -> name != NULL)
       g_free (tree -> name);
     tree -> name = g_strdup (entry);
     gtk_window_set_title (GTK_WINDOW (treeViewWindow), tree -> name);
   }
   g_free (entry);
 }
 DestroyEntryDialog (nameDialog);
}

void OnMenuSaveGraph (GtkMenuItem* saveAsMenu, gpointer data) {
 GtkWidget* dialog;
 GtkFileFilter* svgRawFilter;
 GtkFileFilter* svgRecFilter;
 GtkFileFilter* svgConFilter;
 GtkFileFilter* userFilter;
 gchar* fileName;
 PHYLOTREE* tree;
 PHYLONODE* actNode;

 if (activeTree == NULL) return;
 tree = (PHYLOTREE*) activeTree -> data;
 fileName = NULL;
 dialog = gtk_file_chooser_dialog_new ("Save File", GTK_WINDOW (GETMAINWIN), GTK_FILE_CHOOSER_ACTION_SAVE,
                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "unitled");
 if (tree -> recOR != NULL) {
   svgRecFilter = CreateFileFilter ("Tree with reconstruction in a SVG file (*.svg)", "*.svg", dialog);
   if (tree -> recCons != NULL) {
     actNode = (PHYLONODE*) tree -> root -> data;
     if (actNode -> rec == g_ptr_array_index (tree -> recCons, 0))
       svgConFilter = CreateFileFilter ("Tree with Bremer values in a SVG file (*.svg)", "*.svg", dialog);
     else
       svgConFilter = NULL;
   }
 }
 else {
   svgRecFilter = NULL;
   svgConFilter = NULL;
 }
 svgRawFilter = CreateFileFilter ("Just tree in a SVG file (*.svg)", "*.svg", dialog);
 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
   fileName = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
   userFilter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog));
   if (userFilter == svgRawFilter) {
     fileName = CheckExtention (fileName, "svg");
     WriteSVGFile (fileName, (PHYLOTREE*) activeTree -> data, SVG_NO_REC);
   }
   if ((userFilter == svgRecFilter) && (svgRecFilter != NULL)) {
     fileName = CheckExtention (fileName, "svg");
     WriteSVGFile (fileName, (PHYLOTREE*) activeTree -> data, SVG_WITH_REC);
   }
   if ((userFilter == svgConFilter) && (svgConFilter != NULL)) {
     fileName = CheckExtention (fileName, "svg");
     WriteSVGFile (fileName, (PHYLOTREE*) activeTree -> data, SVG_WITH_SUPP | SVG_WITH_REC);
   }
   g_free (fileName);
 }
 gtk_widget_destroy (dialog);
}

void OnMenuSaveTree (GtkMenuItem* saveAsMenu, gpointer data) {
 GtkWidget* dialog;
 GtkFileFilter* cladoFilter;
 GtkFileFilter* phyRawFilter;
 GtkFileFilter* tntFilter;
 GtkFileFilter* nexusFilter;
 GtkFileFilter* nameFilter;
 GtkFileFilter* userFilter;
 gchar* fileName;

 fileName = NULL;
 dialog = gtk_file_chooser_dialog_new ("Save File", GTK_WINDOW (GETMAINWIN), GTK_FILE_CHOOSER_ACTION_SAVE,
                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "unitled");
 cladoFilter = CreateFileFilter ("Phylogeny (just cladogram) in XML (*.xml)", "*.xml", dialog);
 phyRawFilter = CreateFileFilter ("Phylogeny in phyloXML (*.xml)", "*.xml", dialog);
 tntFilter = CreateFileFilter ("Phylogeny for TNT (*.tnt)", "*.tnt", dialog);
 nexusFilter = CreateFileFilter ("Phylogeny (translate) in Nexus (*.nex)", "*.nex", dialog);
 nameFilter = CreateFileFilter ("Phylogeny (just tree) in Nexus (*.nex)", "*.nex", dialog);
 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
   fileName = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
   userFilter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog));
   if (userFilter == phyRawFilter) {
     fileName = CheckExtention (fileName, "xml");
     WritePhyTree (fileName, (PHYLOTREE*) activeTree -> data);
   }
   else if (userFilter == cladoFilter) {
     fileName = CheckExtention (fileName, "xml");
     WriteCladoTree (fileName, (PHYLOTREE*) activeTree -> data);
   }
   else if (userFilter == tntFilter) {
     fileName = CheckExtention (fileName, "tnt");
     WriteNewickFile (fileName, (PHYLOTREE*) activeTree -> data, USE_TNT);
   }
   else if (userFilter == nexusFilter) {
     fileName = CheckExtention (fileName, "nex");
     WriteNewickFile (fileName, (PHYLOTREE*) activeTree -> data, USE_NEXUS);
   }
   else if (userFilter == nameFilter) {
     fileName = CheckExtention (fileName, "nex");
     WriteNewickFile (fileName, (PHYLOTREE*) activeTree -> data, USE_NEXUS | USE_NAMES);
   }
   g_free (fileName);
 }
 gtk_widget_destroy (dialog);
}

void OnAlign (GtkWidget* menuItem, gpointer data) {
 SFLAG nuSelection;

 nuSelection = tWinData . alignment;
 if (!g_strcmp0 (MENU_TOROOT, (gchar*) data)) {
   nuSelection &= ~ TREE_TOTERM;
   nuSelection |= TREE_TOROOT;
 }
 else if (!g_strcmp0 (MENU_TOTERM, (gchar*) data)) {
   nuSelection &= ~ TREE_TOROOT;
   nuSelection |= TREE_TOTERM;
 }
 else if (!g_strcmp0 (MENU_RAGGED, (gchar*) data)) {
   tWinData . alignment = TREE_RAGGED | TREE_TOROOT;
   gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (tWinData . menuToRoot), TRUE);
   tWinData . alignment = nuSelection;
   nuSelection = TREE_RAGGED | TREE_TOROOT;
   gtk_widget_set_sensitive (tWinData . menuToRoot, TRUE);
   gtk_widget_set_sensitive (tWinData . menuToTerm, FALSE);
 }
 else if (!g_strcmp0 (MENU_ALIGN, (gchar*) data)) {
   nuSelection &=  (TREE_TOROOT | TREE_TOTERM);
   nuSelection |= TREE_ALIGN;
   gtk_widget_set_sensitive (tWinData . menuToRoot, TRUE);
   gtk_widget_set_sensitive (tWinData . menuToTerm, TRUE);
 }
 else if (!g_strcmp0 (MENU_CHRONO, (gchar*) data)) {
   nuSelection = TREE_CHRONO;
   gtk_widget_set_sensitive (tWinData . menuToTerm, FALSE);
   gtk_widget_set_sensitive (tWinData . menuToRoot, FALSE);
 }
 if (tWinData . alignment == nuSelection) return;
 tWinData . alignment = nuSelection;
 DrawTree (TRUE);
}

void OnMenuFitToWin (GtkWidget* menuItem, gpointer data) {
 PHYLOTREE* tree;

 tWinData . width = tWinData . clientX;
 tWinData . height = tWinData . clientY;
 tWinData . originX = tWinData . originY = 0;
 tWinData . endClient = 50;
 tree = (PHYLOTREE*) activeTree -> data;
 tree -> x = tWinData . width;
 tree -> y = tWinData . height;
 DrawTree (TRUE);
}

void OnMenuFitToTerm (GtkWidget* menuItem, gpointer data) {
 PHYLONODE* root;
 PHYLOTREE* tree;

 tree = (PHYLOTREE*) activeTree -> data;
 root = (PHYLONODE*) tree -> root -> data;
 tWinData . width = 40 * root -> level + 10;
 tWinData . height = (10 * (2 * (root -> numTerms - 1))) + 10;
 tWinData . originX = tWinData . originY = 0;
 tWinData . endClient = 50;
 tree -> x = tWinData . width;
 tree -> y = tWinData . height;
 DrawTree (TRUE);
}

void OnMenuSortUp (GtkWidget* menuSort, gpointer data) {
 SortNodes (TREE_TERMS_UP);
 DrawTree (TRUE);
}

void OnMenuSortDown (GtkWidget* menuSort, gpointer data) {
 SortNodes (TREE_TERMS_DOWN);
 DrawTree (TRUE);
}

void OnMenuSortMix (GtkWidget* menuSort, gpointer data) {
 SortNodes (TREE_TERMS_MIX);
 DrawTree (TRUE);
}
void OnMenuSortDef (GtkWidget* menuSort, gpointer data) {
 SortNodes (TREE_TERMS_DEF);
 DrawTree (TRUE);
}

void OnMenuOptions (GtkWidget* menuOption, gpointer data) {
 PHYLOTREE* tree;

 if (activeTree == NULL) return;
 tree = (PHYLOTREE*) activeTree -> data;
 if (tree -> recOR == NULL) return;
 DrawTree (TRUE);
}

/* Prepare the actual tree, or clean the screen */
void DrawTree (SFLAG redraw) {
 GdkRectangle updateRec;

 if (tWinData . pixMap == NULL)
   tWinData . pixMap = gdk_pixmap_new (tWinData . drawable -> window, tWinData . clientX, tWinData . clientY, -1);
 gdk_draw_rectangle (tWinData . pixMap, tWinData . drawable -> style -> white_gc, TRUE, 0, 0, tWinData . clientX, tWinData . clientY);
 if (activeTree != NULL) {
   if (redraw == TRUE)
     PutTreeOnScreen ((PHYLOTREE*) activeTree -> data);
   PaintTree ();
 }
 updateRec . x = 0;
 updateRec . y = 0;
 updateRec . width = tWinData . clientX;
 updateRec . height = tWinData . clientY;
 gdk_window_invalidate_rect (tWinData . drawable -> window, &updateRec, TRUE);
}

/* Calculates tree' screen coordinates */
void PutTreeOnScreen (PHYLOTREE* tree) {
 SREAL sizeX, sizeY;
 PHYLONODE* actNode;
 PHYLONODE* descNode;
 GNode* navNode;
 GNode* navDesc;
 SCOUNTER marginX, marginY, ageSector;
 PangoLayout* lay;

 marginX = 5;
 marginY = 10;
 ageSector = tree -> maxTreeAge;

 actNode = (PHYLONODE*) tree -> root -> data;
 if (tWinData . alignment & TREE_CHRONO) {
   marginX += actNode -> level;
   sizeX = (SREAL) (tWinData . width - (2 * marginX) - tWinData . endClient) / ageSector;
 }
 else
   sizeX = (SREAL) (tWinData . width - (2 * marginX) - tWinData . endClient) / actNode -> level;
 sizeY = (SREAL) (tWinData . height - (2 * marginY)) / (2 * (actNode -> numTerms - 1));
 tWinData . maxX = tWinData . maxY = 0;
 for (navNode = tree -> root; navNode != NULL; ) {
   actNode = (PHYLONODE*) navNode -> data;
   actNode -> actY = actNode -> y * sizeY + marginY;
   if (actNode -> actY > tWinData . maxY)
     tWinData . maxY = actNode -> actY;
   actNode -> topY = actNode -> startY * sizeY + marginY;
   actNode -> downY = actNode -> endY * sizeY + marginY;
   if (g_node_first_child (navNode) == NULL) {
     if ((actNode -> layout == NULL) && (actNode -> name != NULL)) {
       lay = gtk_widget_create_pango_layout (tWinData . drawable, actNode -> name);
       actNode -> layout = lay;
     }
     if (tWinData . alignment & TREE_CHRONO)
       actNode -> actX = actNode -> ageX * sizeX + marginX;
     else if (tWinData . alignment & TREE_ALIGN)
       actNode -> actX = actNode -> maxX * sizeX + marginX;
     else
       actNode -> actX = actNode -> minX * sizeX + marginX;
     if (actNode -> actX > tWinData . maxX)
       tWinData . maxX = actNode -> actX;
   }
   else {
     if (actNode -> layout == NULL)
       actNode -> layout = gtk_widget_create_pango_layout (tWinData . drawable, "");
     if (tWinData . alignment & TREE_CHRONO)
       actNode -> actX = actNode -> ageX * sizeX + marginX;
     else if (tWinData . alignment & TREE_TOROOT)
       actNode -> actX = actNode -> minX * sizeX + marginX;
     else
       actNode -> actX = actNode -> maxX * sizeX + marginX;
     navNode = g_node_first_child (navNode);
     continue;
   }
   while (navNode != NULL) {
     if (g_node_next_sibling (navNode) != NULL) {
       navNode = g_node_next_sibling (navNode);
       break;
     }
     navNode = navNode -> parent;
     if ((navNode != NULL) && (tWinData . alignment & TREE_CHRONO)) {
       actNode = (PHYLONODE*) navNode -> data;
       for (navDesc = g_node_first_child (navNode); navDesc != NULL; navDesc = g_node_next_sibling (navDesc)) {
         descNode = (PHYLONODE*) navDesc -> data;
         if (descNode -> actX <= actNode -> actX + 2)
           actNode -> actX = descNode -> actX - 2;
       }
     }
   }
 }
}

/* Paint a tree on a pixMap */
void PaintTree () {
 PHYLOTREE* tree;
 PHYLONODE* actNode;
 PHYLONODE* tmpNode;
 GNode* navNode;
 GList* navList;
 SINTEGER startX;
 SINTEGER endX;
 SINTEGER startY;
 SINTEGER endY;
 gchar* text;
 SFLAG onConsensus;

 gdk_draw_rectangle (tWinData . pixMap, tWinData . drawable -> style -> white_gc, TRUE, 0, 0, tWinData . clientX, tWinData . clientY);
 tree = (PHYLOTREE*) activeTree -> data;
 onConsensus = FALSE;
 if (tree -> recCons != NULL) {
   actNode = (PHYLONODE*) tree -> root -> data;
   if (actNode -> rec == g_ptr_array_index (tree -> recCons, 0))
     onConsensus = TRUE;
 }
 /* Draw nodes */
 for (navNode = tree -> root; navNode != NULL; ) {
   actNode = (PHYLONODE*) navNode -> data;
   startX = actNode -> actX - tWinData . originX;
   startY = actNode -> actY - tWinData . originY;
   if (navNode -> parent != NULL) {
     tmpNode = (PHYLONODE*) navNode -> parent -> data;
     endX = tmpNode -> actX - tWinData . originX;
   }
   else
     endX = startX - 2;
   /* Draws the horizonthal line */
   if ((startY >= 0) && (startY <= tWinData . clientY)) {
     if (endX < 0)
       endX = 0;
     if ((startX <= tWinData . clientX) && (startX >= 0)) {
       gdk_draw_line (tWinData . pixMap, tWinData . drawable -> style -> black_gc, startX, startY, endX, startY);
       if ((g_node_first_child (navNode) == NULL) && (actNode -> name != NULL))
         gdk_draw_layout (tWinData . pixMap, tWinData . drawable -> style -> black_gc, startX + 5, startY - 5,
                           (PangoLayout*) actNode -> layout);
     }
     else if ((startX >= tWinData . clientX) && (endX <= tWinData . clientX))
       gdk_draw_line (tWinData . pixMap, tWinData . drawable -> style -> black_gc, tWinData . clientX, startY, endX, startY);
     else if (startX < 0) {
       if ((g_node_first_child (navNode) == NULL) && (actNode -> name != NULL))
         gdk_draw_layout (tWinData . pixMap, tWinData . drawable -> style -> black_gc, startX + 5, startY - 5,
                           (PangoLayout*) actNode -> layout);
     }
   }
   if (g_node_first_child (navNode) != NULL) {
     startX = actNode -> actX - tWinData . originX;
     startY = actNode -> topY - tWinData . originY;
     endY = actNode -> downY - tWinData . originY;
     /* Draws the vertical line */
     if ((startX <= tWinData . clientX) && (startX >= 0)) {
       if (endY > tWinData . clientY)
         endY = tWinData . clientY;
       if ((startY <= tWinData . clientY) && (startY >= 0))
         gdk_draw_line (tWinData . pixMap, tWinData . drawable -> style -> black_gc, startX, startY, startX, endY);
       else if ((startY <= 0) && (endY >= 0))
         gdk_draw_line (tWinData . pixMap, tWinData . drawable -> style -> black_gc, startX, 0, startX, endY);
     }
     navNode = g_node_first_child (navNode);
     continue;
   }
   /* Find next node */
   while (navNode != NULL) {
     if (g_node_next_sibling (navNode) != NULL) {
       navNode = g_node_next_sibling (navNode);
       break;
     }
     navNode = navNode -> parent;
   }
 }
 /* Draw results from reconstruction */
 if (tree -> recOR != NULL) {
   actNode = (PHYLONODE*) tree -> root -> data;
   if ((gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (tWinData . menuCommon)) == TRUE) && (onConsensus == TRUE)) {
     actNode = (PHYLONODE*) activeNode -> data;
     if (actNode -> alloSet != NULL) {
       for (navList = actNode -> alloSet -> nodeList; navList != NULL; navList = g_list_next (navList)) {
         actNode = (PHYLONODE*) navList -> data;
         if (actNode -> tree != tree) continue;
         startX = actNode -> actX - tWinData . originX;
         startY = actNode -> actY - tWinData . originY;
         if ((startX <= tWinData . clientX) && (startX >= 0) && (startY <= tWinData . clientY) && (startY >= 0)) {
           if (actNode -> rec -> nodeFlag & REMOV_NODE) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
           }
           else if (actNode -> rec -> nodeFlag & TIME_LAG) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . greyPen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
           }
           else if (actNode -> rec -> removSet != NULL) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
             gdk_draw_line (tWinData . pixMap, tWinData . drawable -> style -> black_gc,
                              startX -2, startY - 2, startX + 2, startY + 2);
             tmpNode = actNode -> rec -> removSet;
             endY = tmpNode -> actY - tWinData . originY - 2;
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, endY, 5, 5);
             gdk_draw_arc (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, endY, 5, 5, 0, (360 * 64));
           }
           else
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, TRUE, startX - 2, startY - 2, 5, 5);
         }
       }
     }
   }
   else if ((gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (tWinData . menuSupported)) == TRUE) && (onConsensus == TRUE)) {
     for (navNode = tree -> root; navNode != NULL; ) {
       actNode = (PHYLONODE*) navNode -> data;
       if ((actNode -> rec -> nodeFlag & VIC_NODE) && (actNode -> alloSet != NULL) && (actNode -> alloSet -> numNodes > 0)) {
         startX = actNode -> actX - tWinData . originX;
         startY = actNode -> actY - tWinData . originY;
         if ((startX <= tWinData . clientX) && (startX >= 0) && (startY <= tWinData . clientY) && (startY >= 0)) {
           if (actNode -> rec -> nodeFlag & REMOV_NODE) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
           }
           else if (actNode -> rec -> nodeFlag & TIME_LAG) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . greyPen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
           }
           else if (actNode -> rec -> removSet != NULL) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
             gdk_draw_line (tWinData . pixMap, tWinData . drawable -> style -> black_gc,
                              startX -2, startY - 2, startX + 2, startY + 2);
             tmpNode = actNode -> rec -> removSet;
             endY = tmpNode -> actY - tWinData . originY - 2;
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, endY, 5, 5);
             gdk_draw_arc (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, endY, 5, 5, 0, (360 * 64));
           }
           else
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, TRUE, startX - 2, startY - 2, 5, 5);
         }
       }
       if (g_node_first_child (navNode) != NULL) {
         navNode = g_node_first_child (navNode);
         continue;
       }
       /* Find next node */
       while (navNode != NULL) {
         if (g_node_next_sibling (navNode) != NULL) {
           navNode = g_node_next_sibling (navNode);
           break;
         }
         navNode = navNode -> parent;
       }
     }
   }
   else {
     for (navNode = tree -> root; navNode != NULL; ) {
       actNode = (PHYLONODE*) navNode -> data;
       startX = actNode -> actX - tWinData . originX;
       startY = actNode -> actY - tWinData . originY;
       if ((startX <= tWinData . clientX) && (startX >= 0) && (startY <= tWinData . clientY) && (startY >= 0)) {
         if (actNode -> rec -> nodeFlag & VIC_NODE) {
           if (actNode -> rec -> nodeFlag & REMOV_NODE) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
           }
           else if (actNode -> rec -> nodeFlag & TIME_LAG) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . greyPen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
           }
           else if (actNode -> rec -> removSet != NULL) {
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, startY - 2, 5, 5);
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
             gdk_draw_line (tWinData . pixMap, tWinData . drawable -> style -> black_gc,
                              startX -2, startY - 2, startX + 2, startY + 2);
             tmpNode = actNode -> rec -> removSet;
             endY = tmpNode -> actY - tWinData . originY - 2;
             gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, endY, 5, 5);
             gdk_draw_arc (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, endY, 5, 5, 0, (360 * 64));
           }
           else
             gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, TRUE, startX - 2, startY - 2, 5, 5);
           if ((onConsensus == TRUE) && (actNode -> layout != NULL) &&
                (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (tWinData . menuBremer)) == TRUE)) {
             if (actNode -> bremer > actNode -> tree -> worst)
               text = g_strdup_printf ("?> %.2f", actNode -> tree -> worst - actNode -> tree -> best);
             else
               text = g_strdup_printf ("%.2f", actNode -> bremer - actNode -> tree -> best);
             CheckRealStr (text);
             pango_layout_set_text (actNode -> layout, text, -1);
             g_free (text);
             gdk_draw_layout (tWinData . pixMap, tWinData . drawable -> style -> black_gc, startX + 5, startY - 5,
                           (PangoLayout*) actNode -> layout);
           }
         }
         else if (actNode -> rec -> nodeFlag & REMOV_NODE) {
           gdk_draw_rectangle (tWinData . pixMap, tWinData . whitePen, TRUE, startX - 2, startY - 2, 5, 5);
           gdk_draw_arc (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5, 0, (360 * 64));
         }
       }
       if (g_node_first_child (navNode) != NULL) {
         navNode = g_node_first_child (navNode);
         continue;
       }
       /* Find next node */
       while (navNode != NULL) {
         if (g_node_next_sibling (navNode) != NULL) {
           navNode = g_node_next_sibling (navNode);
           break;
         }
         navNode = navNode -> parent;
       }
     }
   }
 }
 /* Draw the position of the selected node */
 actNode = (PHYLONODE*) activeNode -> data;
 if (actNode -> tree == tree) {
   startX = actNode -> actX - tWinData . originX;
   startY = actNode -> actY - tWinData . originY;
   if ((startX <= tWinData . clientX) && (startX >= 0) && (startY <= tWinData . clientY) && (startY >= 0)) {
     gdk_draw_rectangle (tWinData . pixMap, tWinData . greenPen, TRUE, startX - 2, startY - 2, 5, 5);
     gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
   }
   if ((actNode -> rec != NULL) && (actNode -> rec -> nodeFlag & VIC_NODE)) {
     startX = actNode -> rec -> setA -> actX - tWinData . originX;
     startY = actNode -> rec -> setA -> actY - tWinData . originY;
     if ((startX <= tWinData . clientX) && (startX >= 0) && (startY <= tWinData . clientY) && (startY >= 0)) {
       gdk_draw_rectangle (tWinData . pixMap, tWinData . bluePen, TRUE, startX - 2, startY - 2, 5, 5);
       gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
     }
     startX = actNode -> rec -> setB -> actX - tWinData . originX;
     startY = actNode -> rec -> setB -> actY - tWinData . originY;
     if ((startX <= tWinData . clientX) && (startX >= 0) && (startY <= tWinData . clientY) && (startY >= 0)) {
       gdk_draw_rectangle (tWinData . pixMap, tWinData . redPen, TRUE, startX - 2, startY - 2, 5, 5);
       gdk_draw_rectangle (tWinData . pixMap, tWinData . blackPen, FALSE, startX - 2, startY - 2, 5, 5);
     }
   }
 }
}

GNode* SearchNearestPoint (gint x, gint y) {
 GNode* navNode;
 GNode* toRet;
 PHYLONODE* actNode;
 PHYLOTREE* tree;
 SINTEGER difX, difY, bestDif, actDif;

 toRet = NULL;
 bestDif = 7;
 tree = (PHYLOTREE*) activeTree -> data;
 for (navNode = tree -> root; navNode != NULL; ) {
   actNode = (PHYLONODE*) navNode -> data;
   difX = x - actNode -> actX;
   difX = (difX >= 0) ? difX : - difX;
   /* The x-coordinate of the node exceeds the search coordinate, then, no descendant of the node need to
      be considered */
   if ((difX > 3) && (actNode -> actX > x)) {
     while (navNode != NULL) {
       if (g_node_next_sibling (navNode) != NULL) {
         navNode = g_node_next_sibling (navNode);
         break;
       }
       navNode = navNode -> parent;
     }
     continue;
   }
   difY = y - actNode -> actY;
   difY = (difY >= 0) ? difY : - difY;
   actDif = difX + difY;
   if (actDif < bestDif) {
     bestDif = actDif;
     toRet = navNode;
   }
   if (actDif == 0) break;
   navNode = GetNextNode (navNode);
   /* There are no more nodes to see */
   if (navNode == tree -> root) break;
 }
 return toRet;
}

void OnChangeNodeData (GNode* node) {
 NODEDATADIALOG* dataDialog;
 PHYLONODE* actNode;
 gchar* text;
 SFLAG mode;
 SFLAG change;
 SCOUNTER age;
 PangoLayout* lay;

 mode = (GetGridState () == TRUE) ? FALSE : TRUE;
 dataDialog = NodeDataDialog (node, mode);
 change = FALSE;
 if ((gtk_dialog_run (GTK_DIALOG (dataDialog -> dialog)) == GTK_RESPONSE_ACCEPT) && (mode == TRUE)) {
   actNode = (PHYLONODE*) node -> data;
   text = g_strdup_printf (gtk_entry_get_text (GTK_ENTRY (dataDialog -> nameEntry)));
   if (actNode -> name != NULL)
     g_free (actNode -> name);
   actNode -> name = g_strdup (text);
   g_free (text);
   if (actNode -> term != NULL) {
     actNode -> term -> name = AddSynonim (actNode -> term, actNode -> name);
   }
   if (activeNode == node)
     OnChangeRec ();
   if (actNode -> layout != NULL) {
     lay = (PangoLayout*) actNode -> layout;
     pango_layout_set_text (lay, actNode -> name, -1);
   }
   text = g_strdup_printf (gtk_entry_get_text (GTK_ENTRY (dataDialog -> ageEntry)));
   SetCommandLine (text);
   g_free (text);
   if (GetCmdNumber (&age) != FALSE) {
     if ((age >= 0) && (SetNodeAge (node, age, FALSE) == TRUE)) {
       gtk_widget_set_sensitive (tWinData . menuChrono, TRUE);
       if (tWinData . alignment & TREE_CHRONO)
         change = TRUE;
     }
   }
   DrawTree (change);
 }
 DestroyNodeDataDialog (dataDialog);
}
